package channel

import (
	"gitee.com/lipore/go-nio/pkg/buffer"
	"gitee.com/lipore/go-nio/pkg/frame"
	"gitee.com/lipore/go-nio/pkg/transport"
	"sync"
)

type (
	Channel interface {
		sync.Locker
		ID() int64
		Write(f frame.Frame)
		Transport() transport.Transport
		Pipeline() *Pipeline
		SetPipeline(p *Pipeline)
		InboundBuffer() *buffer.Buffer
		Close() error
	}
)

type channel struct {
	sync.Mutex
	pipeline   *Pipeline
	closeOnce  sync.Once
	transport  transport.Transport
	inboundBuf *buffer.Buffer
}

func NewChannel(p *Pipeline, t transport.Transport) Channel {
	return &channel{
		pipeline:   p,
		transport:  t,
		inboundBuf: new(buffer.Buffer),
	}
}

func (c *channel) ID() int64 {
	return c.transport.ID()
}

func (c *channel) Write(f frame.Frame) {
	c.pipeline.FireChannelOutbound(c, f)
}

func (c *channel) Pipeline() *Pipeline {
	return c.pipeline
}

func (c *channel) SetPipeline(p *Pipeline) {
	c.pipeline = p
}

func (c *channel) Transport() transport.Transport {
	return c.transport
}

func (c *channel) InboundBuffer() *buffer.Buffer {
	return c.inboundBuf
}

func (c *channel) Close() error {
	var err error
	c.closeOnce.Do(
		func() {
			err = c.transport.Close()
		})
	return err
}
